﻿using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace socket_client
{
    public class TcpSocket
    {
        public async Task SendFileAsync(string filePath, string serverIp, int serverPort)
        {
            // 文件检查逻辑优化
            if (!File.Exists(filePath))
            {
                AsyncFileLogger.WriteLog($"文件未找到: {filePath}");
                throw new FileNotFoundException("文件未找到", filePath);
            }

            using (TcpClient client = new TcpClient())
            {
                try
                {
                    // 1. 连接服务端（带超时）
                    await ConnectWithTimeoutAsync(client, serverIp, serverPort, 5000);
                    AsyncFileLogger.WriteLog($"已连接到服务端: {serverIp}:{serverPort}");

                    using (NetworkStream stream = client.GetStream())
                    {
                        FileInfo fileInfo = new FileInfo(filePath);
                        string fileName = fileInfo.Name;
                        long fileSize = fileInfo.Length;

                        // 2. 发送元数据
                        await SendMetadataAsync(stream, fileName, fileSize);
                        AsyncFileLogger.WriteLog($"[元数据已发送] 文件名: {fileName}, 大小: {fileSize} bytes");

                        // 3. 等待服务端确认
                        string ack = await ReadStringAsync(stream);
                        if (ack != "READY")
                            throw new Exception($"服务端未准备就绪: {ack}");

                        // 4. 发送文件内容
                        await SendFileContentAsync(client, stream, filePath, fileSize);
                        AsyncFileLogger.WriteLog("[文件内容发送完成]");

                        // 5. 接收最终确认
                        string finalAck = await ReadStringAsync(stream);
                        AsyncFileLogger.WriteLog($"服务端响应: {finalAck}");
                    }
                }
                catch (SocketException ex)
                {
                    AsyncFileLogger.WriteLog($"套接字错误: {ex.SocketErrorCode}");
                }
                catch (Exception ex)
                {
                    AsyncFileLogger.WriteLog($"客户端错误: {ex.Message}");
                    throw;
                }
            }
        }

        private async Task ConnectWithTimeoutAsync(TcpClient client, string ip, int port, int timeoutMs)
        {
            var connectTask = client.ConnectAsync(ip, port);
            var timeoutTask = Task.Delay(timeoutMs);

            var completedTask = await Task.WhenAny(connectTask, timeoutTask);
            if (completedTask == timeoutTask)
            {
                AsyncFileLogger.WriteLog("连接服务端超时"); 
                throw new TimeoutException("连接服务端超时");
            }

            // 添加连接状态验证
            if (!client.Connected)
            {
                AsyncFileLogger.WriteLog("连接未建立");
                throw new InvalidOperationException("连接未建立");
            }
        }

        private async Task SendMetadataAsync(NetworkStream stream, string fileName, long fileSize)
        {
            byte[] nameBytes = Encoding.UTF8.GetBytes(fileName);
            byte[] nameLengthBytes = BitConverter.GetBytes(nameBytes.Length);
            await stream.WriteAsync(nameLengthBytes, 0, 4);

            await stream.WriteAsync(nameBytes, 0, nameBytes.Length);

            byte[] sizeBytes = BitConverter.GetBytes(fileSize);
            await stream.WriteAsync(sizeBytes, 0, 8);
        }

        private async Task SendFileContentAsync(TcpClient client, NetworkStream stream, string filePath, long fileSize)
        {
            using (FileStream fileStream = File.OpenRead(filePath))
            {
                byte[] buffer = new byte[65536];
                long totalSent = 0;

                while (totalSent < fileSize)
                {
                    CheckConnection(client); 

                    int bytesToSend = (int)Math.Min(buffer.Length, fileSize - totalSent);
                    int bytesRead = await fileStream.ReadAsync(buffer, 0, bytesToSend);

                    await stream.WriteAsync(buffer, 0, bytesRead);
                    totalSent += bytesRead;
                    AsyncFileLogger.WriteLog($"已发送: {totalSent}/{fileSize} bytes");
                }
            }
        }

        private async Task<string> ReadStringAsync(NetworkStream stream)
        {
            byte[] lengthBytes = new byte[4];
            await ReadExactAsync(stream, lengthBytes, 0, 4);
            int length = BitConverter.ToInt32(lengthBytes, 0);

            byte[] buffer = new byte[length];
            await ReadExactAsync(stream, buffer, 0, length);
            return Encoding.UTF8.GetString(buffer);
        }

        private async Task ReadExactAsync(NetworkStream stream, byte[] buffer, int offset, int count)
        {
            int totalRead = 0;
            while (totalRead < count)
            {
                int bytesRead = await stream.ReadAsync(buffer, offset + totalRead, count - totalRead);
                if (bytesRead == 0)
                {
                    AsyncFileLogger.WriteLog("连接中断");
                    throw new IOException("连接中断");
                }
                totalRead += bytesRead;
            }
        }
        private void CheckConnection(TcpClient client)
        {
            if (client == null || !client.Connected)
            {
                AsyncFileLogger.WriteLog("连接已断开");
                throw new InvalidOperationException("连接已断开");
            }
        }
    }
}